/*
 * DictionaryTermSerializer.h
 *
 *  Created on: Oct 22, 2012
 *      Author: m
 */

#ifndef DICTIONARYTERMSERIALIZER_H_
#define DICTIONARYTERMSERIALIZER_H_

#include <string>
#include <cstring>
#include <memory>
#include <cassert>
#include "DictionaryTerm.h"
#include "../../physical_layer/physical_layer_commons.h"

#define _DICTIONARY_TERM_STRING_MAX_LENGTH 40

/*
 * Definiciones Lógicas de un DictionaryTerm:
 *
 *  Definición Larga:
 *  DictionaryTerm( randomKey:E4, reserved:E4, term:C40 );
 *  TOTAL : 48 bytes
 *
 *  Definición Corta:
 *  DictionaryTerm( reserved:E4, term:C40 );
 *  TOTAL : 44 bytes
 *
 */


class DictionaryTermSerializer
{

public:
    virtual ~DictionaryTermSerializer(){};
    virtual physical::UP_byteStream serialize( DictionaryTerm* term ) = 0;
    virtual std::shared_ptr<DictionaryTerm> deserialize( const physical::byteStream block ) = 0;
    virtual size_t getSerializationLength() = 0;

};



// Serializador para la definición lógica corta ( sin el nº random )

class DictionaryTermShortSerializer : public DictionaryTermSerializer
{

private:
    struct __attribute__ ((__packed__)) logicDefinition
    {

    public:
        int reserved;
        char term[_DICTIONARY_TERM_STRING_MAX_LENGTH];

        logicDefinition( DictionaryTerm* dictionaryTerm )
        {
            reserved  = dictionaryTerm->getReserved();

            memcpy( term, dictionaryTerm->getTerm() , _DICTIONARY_TERM_STRING_MAX_LENGTH );
            term[_DICTIONARY_TERM_STRING_MAX_LENGTH-1] = '\0';

#ifndef NDEBUG
            // A continuación se rellenan todos los bytes excedentes del bloque con el valor 0xFF,
            //  esto solo se hace en modo debug para obtener un resultado predecible.
            // termLength se calcula incluyendo el '\0'
            size_t termLength = strlen(term)+1;
            char * unusedBytes = term+termLength;
            memset( unusedBytes, 0xFF, _DICTIONARY_TERM_STRING_MAX_LENGTH-termLength );
#endif

        };
    };

public:

    physical::UP_byteStream serialize( DictionaryTerm* term )
    {
        logicDefinition* serialization = new logicDefinition(term);
        return physical::UP_byteStream( (physical::byte*)serialization );
    };

    std::shared_ptr<DictionaryTerm> deserialize( const physical::byteStream block )
    {
        logicDefinition* buffer = (logicDefinition*)block;

        DictionaryTerm* ptr = new DictionaryTerm( buffer->term, 0, buffer->reserved );

        return std::shared_ptr<DictionaryTerm> ( ptr );
    };

    size_t getSerializationLength()
    {
        return sizeof( logicDefinition );
    };
};

// Serializador para la definición lógica Larga ( incluye el nº random )

class DictionaryTermLongSerializer : public DictionaryTermSerializer
{

private:
    struct __attribute__ ((__packed__)) logicDefinition
    {

    public:
        int randomKey;
        int reserved;
        char term[_DICTIONARY_TERM_STRING_MAX_LENGTH];

        logicDefinition( DictionaryTerm* dictionaryTerm )
        {
            randomKey = dictionaryTerm->getRandomKey();
            reserved  = dictionaryTerm->getReserved();

            memcpy( term, dictionaryTerm->getTerm() , _DICTIONARY_TERM_STRING_MAX_LENGTH );
            term[_DICTIONARY_TERM_STRING_MAX_LENGTH-1] = '\0';

#ifndef NDEBUG
            // A continuación se rellenan todos los bytes excedentes del bloque con el valor 0xFF,
            //  esto solo se hace en modo debug para obtener un resultado predecible.
            // termLength se calcula incluyendo el '\0'
            size_t termLength = strlen(term)+1;
            char * unusedBytes = term+termLength;
            memset( unusedBytes, 0xFF, _DICTIONARY_TERM_STRING_MAX_LENGTH-termLength );
#endif

        };
    };

public:
    physical::UP_byteStream serialize( DictionaryTerm* term )
    {
        logicDefinition* serialization = new logicDefinition(term);
        return physical::UP_byteStream( (physical::byte*)serialization );
    };

    std::shared_ptr<DictionaryTerm> deserialize( const physical::byteStream block )
    {
        logicDefinition* buffer = (logicDefinition*)block;

        DictionaryTerm* ptr = new DictionaryTerm( buffer->term, buffer->randomKey, buffer->reserved );

        return std::shared_ptr<DictionaryTerm> ( ptr );
    };

    size_t getSerializationLength()
    {
        return sizeof( logicDefinition );
    };

};

#endif /* DICTIONARYTERMSERIALIZER_H_ */
